package com.michael.demos.springboot.valid.handler;

import com.michael.demos.springboot.common.result.JsonResult;
import com.michael.demos.springboot.common.result.R;
import com.michael.demos.springboot.valid.exception.ParamsErrorException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 类功能描述:
 * <pre>
 *   全局异常处理器
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/7/29 12:01
 */
@Slf4j
@RestControllerAdvice("com.michael.demos.springboot.valid")
public class GlobalExceptionHandler {

    /**
     * 未传参数异常处理器
     *
     * @param e 未传参数异常
     *
     * @return JsonResult
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public JsonResult missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        return R.paramError().setMsg("请求参数 [" + e.getParameterName() + "] 不能为空");
    }

    /**
     * 参数校验异常处理器
     *
     * @param e 参数校验异常
     *
     * @return JsonResult
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public JsonResult constraintViolationExceptionHandler(ConstraintViolationException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();
        if (!violationSet.isEmpty()) {
            String message = violationSet.iterator().next().getMessage();
            return R.paramError().setMsg(message);
        }
        return R.paramError();
    }


    /**
     * 缺少请求体异常处理器
     *
     * @param e 缺少请求体异常
     *
     * @return JsonResult
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public JsonResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        return R.paramError().setMsg("参数异常");
    }

    /**
     * 参数类型匹配异常
     *
     * @param e 参数类型匹配
     *
     * @return JsonResult
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public JsonResult methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        return R.paramError().setMsg("参数异常");
    }

    /**
     * 参数效验异常处理器
     *
     * @param e 参数验证异常
     *
     * @return ResponseInfo
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResult parameterExceptionHandler(MethodArgumentNotValidException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                return R.paramError().setMsg(fieldError.getDefaultMessage());
            }
        }
        return R.paramError();
    }

    /**
     * 自定义参数错误异常处理器
     *
     * @param e 自定义参数
     *
     * @return ResponseInfo
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ParamsErrorException.class})
    public JsonResult paramExceptionHandler(ParamsErrorException e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (!StringUtils.isEmpty(e.getMessage())) {
            return R.paramError().setMsg(e.getMessage());
        }
        return R.paramError();
    }

    /**
     * 其它错误异常处理器
     *
     * @param e 异常参数
     *
     * @return ResponseInfo
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({Exception.class})
    public JsonResult paramExceptionHandler(Exception e) {
        if (log.isErrorEnabled()) {
            log.error("", e);
        }
        return R.unknowError();
    }
}
